#include <mysql/mysql.h>

#include "MysqlConnPool.h"

LoggerPtr MysqlConnPool::_logger(Logger::getLogger("MysqlConnPool"));


int MysqlConnPool::init(const char * svr_ip, unsigned short svr_port, const char * svr_username, const char * svr_password, \
                        const char * db_name, int pool_max_size) {
	if (NULL == svr_ip || svr_port < 1 || NULL == svr_username || NULL == svr_password || NULL == db_name || \
			pool_max_size < 1) {
		LOG4CXX_ERROR(_logger, "init error, invalid args");
		return -1;
	}
	_svr_ip = svr_ip;
	_svr_port = svr_port;
	_svr_username = svr_username;
	_svr_password = svr_password;
	_db_name = db_name;
	_pool_max_size = pool_max_size;
	pthread_mutex_init(&_mutex, NULL);
	for (int i = 0; i < _pool_max_size; i++) {
		MYSQL_POOL_ITEM item;
		item.mysql = NULL; 
		item.is_in_use = false;
		_conns.push_back(item);
	}
	LOG4CXX_INFO(_logger, "init ok, svr_ip:" << svr_ip << ", svr_port:" << svr_port << ", svr_username:" << svr_username \
			<< ", svr_password:" << svr_password << ", pool_max_size:" << pool_max_size);
	return 1;
}

int MysqlConnPool::get(MysqlConnPtr & ptr) {
	pthread_mutex_lock(&_mutex);
	int i = 0;
	for (vector<MYSQL_POOL_ITEM>::iterator iter = _conns.begin(); _conns.end() != iter; iter++, i++) {
		if (!iter->is_in_use) {
			MYSQL * mysql = iter->mysql;
			if (NULL == mysql || 0 != mysql_ping(mysql)) {
				int ret = reconnect(i);
				if (ret < 0) {
					pthread_mutex_unlock(&_mutex);
					return -1;
				}
			}	
			ptr.assign(_conns[i].mysql, i, this);
			iter->is_in_use = true;
			pthread_mutex_unlock(&_mutex);
			return 1;
		}
	}
	pthread_mutex_unlock(&_mutex);
	LOG4CXX_ERROR(_logger, "could not get mysql connecton in pool, all the connection are in use, pool size:" << \
			_pool_max_size << ", svr_ip:" << _svr_ip);
	return -2;
}

int MysqlConnPool::reconnect(int index) {
	if (index < 0 || index >= _pool_max_size) {
		LOG4CXX_ERROR(_logger, "reconnect error, invalid index");
		return -1;
	}
	MYSQL * mysql = mysql_init(NULL);
	MYSQL * t = mysql_real_connect(mysql, _svr_ip.c_str(), _svr_username.c_str(), _svr_password.c_str(), _db_name.c_str(), \
			_svr_port, NULL, 0);
	if (NULL == t) {
		LOG4CXX_ERROR(_logger, "connect to mysql errror:" <<  mysql_error(mysql));
		mysql_close(mysql);
		return -2;
	}
	LOG4CXX_INFO(_logger, "reconnect to mysql server ok, svr_ip:" << _svr_ip << ", index:" << index << ", max pool size:" \
			<< _pool_max_size);
	MYSQL_POOL_ITEM & item = _conns[index];
	if (NULL != item.mysql) mysql_close(item.mysql);
	item.mysql = mysql;
	item.is_in_use = false;
	return 1;
}

int MysqlConnPool::release(const int index) {
	if (index < 0 || index >= _pool_max_size) {
		LOG4CXX_ERROR(_logger, "release mysql conn error, invalid index");
		return -1;
	}
	pthread_mutex_lock(&_mutex);
	MYSQL_POOL_ITEM & item = _conns[index];
	item.is_in_use = false;
	pthread_mutex_unlock(&_mutex);
	return 1;
}
